package org.safa.stats;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

public class Statistics {
	//public final static Statistics INSTANCE = new Statistics();
	private HashMap<String,HashMap<String,Double>> hmHM = new HashMap<String,HashMap<String,Double>>();
	private HashMap<String,LinkedList<Double>> hmLL = new HashMap<String,LinkedList<Double>>();

	/*
	 * { NAME => { accum = accum, average = average, count = count } }
	 * ......
	 * 
	 */
	private Statistics(){}
	
	private static class statsHolder {
		public final static Statistics INSTANCE = new Statistics();
	}
	public static Statistics getInstance(){
		return statsHolder.INSTANCE;
	}
	
	public void	updateStatistic(String name, Double val)
	{
		HashMap<String,Double> tHM = new HashMap<String,Double>();
		Double accum = null;
		Double average = null;
		Double count = null;
		Double min = null;
		Double max = null;

			if (!hmHM.containsKey(name))
			{
				initStat(name);
				initQueue(name);
			}
			//get current hashmap for this metric
			tHM = hmHM.get(name);
			
			accum=tHM.get("accum");
			accum+=val;
			tHM.put("accum",accum);
			
			count=tHM.get("count");
			count++;
			tHM.put("count",count);
			
			average=tHM.get("average");
			average=accum/count;
			tHM.put("average",average);
			
			min=tHM.get("min");
			if(val < min)				
				min=val;
			tHM.put("min",min);
			
			max=tHM.get("max");
			if(val > max)				
				max=val;
			tHM.put("max",max);
			
			updateQueue(name,val);
			tHM.put("rollavg",averageQueue(name));
			
			//put updated hashmap for this metric
			hmHM.put(name,tHM);
	}
	/*
	 * input: a HashMap of names and values to update
	 */
	public void updateStatistics(HashMap<String,Double> hm)
	{
		for(String key: hm.keySet())
		{
			updateStatistic(key, hm.get(key));			
		}
	}
	/*
	 * input: the name of a statistic to initialize
	 * min - initialized at 999999999
	 */
	private void initStat(String name)
	{
		HashMap<String,Double> tHM = new HashMap<String,Double>();
		tHM.put("accum", 0.0);
		tHM.put("average", 0.0);
		tHM.put("count", 0.0);
		tHM.put("min", 999999999.0);
		tHM.put("max", 0.0);
		tHM.put("rollavg", 0.0);
		
		hmHM.put(name, tHM);
	}
	/*
	 * input: a List of stat names to initialize
	 */
	public void initStats(List<String> strL)
	{
		for(String s: strL)
		{
			initStat(s);
		}
	}
	/*
	 * input: get a statistics information
	 */
	public HashMap<String,Double> getStat(String name)
	{
		HashMap<String,Double> tHM = new HashMap<String,Double>();
		
		if(hmHM.containsKey(name))
		{
			tHM = hmHM.get(name);
		} else {
			tHM.put("accum",-1.0);
			tHM.put("average",-1.0);
			tHM.put("count",-1.0);
			tHM.put("min", -1.0);
			tHM.put("max", -1.0);
			tHM.put("rolavg", -1.0);
		}
		return tHM;
	}
	/*
	 * input:
	 * output: returns the entire current group of 
	 * statistics in a HashMap<String,HashMap<String,Double>>
	 */
	public HashMap<String,HashMap<String,Double>> getStats()
	{
		HashMap<String,HashMap<String,Double>> thmHM = new HashMap<String,HashMap<String,Double>>();
		HashMap<String,Double> tHM = new HashMap<String,Double>();

		if (!hmHM.isEmpty())
		{
			thmHM = hmHM;
		} else
		{
			tHM.put("nodata",-1.0);
			thmHM.put("nodata",tHM);
		}
		
		return thmHM;
	}
	/*
	 * input:
	 * output: resets the statistics
	 */
	public void resetStats()
	{
		for (String key : hmHM.keySet())
		{
			initStat(key);
		}
		for (String key2 : hmLL.keySet())
		{
			initQueue(key2);
		}
	}
	private void initIfNew(String name)
	{
		if (!hmHM.containsKey(name))
		{
			initStat(name);
		}
		
	}
	private void initQueue(String name)
	{
		 LinkedList<Double> LL= new LinkedList<Double>(); 

		 if (!hmLL.containsKey(name))
		 {
				//init the queue
			 LL.add(0.0);
			 hmLL.put(name, LL);
				
		 }
	}
	private void updateQueue(String name, Double val)
	{
		LinkedList<Double> LL= new LinkedList<Double>(); 

		if(hmLL.containsKey(name))
		{
			LL = hmLL.get(name);
			if(LL.size()>10)
				LL.removeFirst();
			LL.addLast(val);
			
			hmLL.put(name, LL);
		}
	}
	private Double averageQueue(String name)
	{
		 Double ret_Double = -1.1;
		 Double sum = 0.0;
		 LinkedList<Double> LL= new LinkedList<Double>(); 
		 
		 if(hmLL.containsKey(name))
		 {
			 LL = hmLL.get(name);
			 for(int i=0;i<LL.size(); i++)
			 {
				sum+=LL.get(i);
			 }
			 
			 ret_Double = sum / LL.size();
		 } 
		 
		 return ret_Double;
	}

}
